﻿/***************************************************************************
	Copyright (C) 2010 RapidWebDev Organization (Author: Eunge, Legal Name: Jian Liu, Email: eunge.liu@gmail.com)

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
 ***************************************************************************/

using System;
using System.IO;
using System.Data;
using System.Data.OleDb;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Configuration;
using System.Linq;
using System.Data.Linq;
using System.Threading;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using BaoJianSoft.Web.Extensions.Controls;
using BaoJianSoft.Common;
using BaoJianSoft.Web.Extensions.Properties;

namespace BaoJianSoft.Web.Extensions.DynamicPages
{
    /// <summary>
    /// Excel upload panel.
    /// </summary>
    public sealed class ExcelUploadPanel : Panel
    {
        private GridViewPanel GridViewSuccess, GridViewFailure;
        private MessagePanel messagePanel;

        /// <summary>
        /// Construct Excel Upload Panel.
        /// </summary>
        public ExcelUploadPanel(IExcelParser parser)
        {
            this.Parser = parser;
            this.PageSize = 100;
        }

        /// <summary>
        /// Set/get excel parser.
        /// </summary>
        public IExcelParser Parser { get; private set; }

        /// <summary>
        /// Set/get page size for displaying success/failure upload records. 
        /// The default value is 100.
        /// </summary>
        public int PageSize { get; set; }

        /// <summary>
        /// Get successful uploaded record count.
        /// </summary>
        public int SuccessCount
        {
            get
            {
                if (this.Uploaded == null) return 0;
                return this.Uploaded.Tables[ExcelParser.SUCCESS].Rows.Count;
            }
        }

        /// <summary>
        /// Get failure uploaded record count.
        /// </summary>
        public int FailureCount
        {
            get
            {
                if (this.Uploaded == null) return 0;
                return this.Uploaded.Tables[ExcelParser.FAILURE].Rows.Count;
            }
        }

        /// <summary>
        /// Set/get dataset for uploaded excel. 
        /// </summary>
        private DataSet Uploaded
        {
            get { return HttpContext.Current.Session[string.Format("ExcelUpload::{0}", SessionManager.ObjectId)] as DataSet; }
            set { HttpContext.Current.Session[string.Format("ExcelUpload::{0}", SessionManager.ObjectId)] = value; }
        }

        /// <summary>
        /// Called when user uploads a excel file and web server has stored it into local disk.
        /// </summary>
        /// <param name="excelFilePath"></param>
        public void Upload(string excelFilePath)
        {
            try
            {
                this.Uploaded = this.Parser.Parse(excelFilePath);

                int successCount = this.Uploaded.Tables[ExcelParser.SUCCESS].Rows.Count;
                int failureCount = this.Uploaded.Tables[ExcelParser.FAILURE].Rows.Count;
                this.GridViewSuccess.DataBind(0);
                this.GridViewFailure.DataBind(0);

                string message = string.Format(Resources.ExcelHaveNotCommitToDatabase, successCount, failureCount);
                if (failureCount == 0)
                {
                    this.messagePanel.ShowConfirm(message);
                }
                else
                {
                    this.messagePanel.ShowWarning(message);
                }
            }
            catch (InvalidOperationException exp)
            {
                this.messagePanel.ShowWarning(exp.Message);
            }
            catch (Exception exp)
            {
                Logger.Instance(this).Error(exp);
                this.messagePanel.ShowError(Resources.OccurExceptionHaveLogTryLater);
            }
        }

        /// <summary>
        /// Clear all cached failure or successs upload records.
        /// </summary>
        public void Clear()
        {
            try
            {
                this.Uploaded = null;
                this.GridViewSuccess.DataBind(0);
                this.GridViewFailure.DataBind(0);
            }
            catch (InvalidOperationException exp)
            {
                this.messagePanel.ShowWarning(exp.Message);
            }
            catch (Exception exp)
            {
                Logger.Instance(this).Error(exp);
                this.messagePanel.ShowError(Resources.OccurExceptionHaveLogTryLater);
            }
        }

        /// <summary>
        /// Save the successful uploaded records.
        /// </summary>
        public void Save()
        {
            try
            {
                IList objects = this.Parser.Parse(this.Uploaded);
                ExcelParserObjectEventArgs e = new ExcelParserObjectEventArgs(objects, objects.Count);
                this.Parser.OnSaving(e);

                // clear caching
                this.Uploaded = null;
                this.GridViewSuccess.DataBind(0);
                this.GridViewFailure.DataBind(0);

                this.messagePanel.ShowConfirm(Resources.SaveUploadedDataSuccessfully);

                this.Parser.OnSaved(e);
            }
            catch (ThreadAbortException)
            {
            }
            catch (InvalidOperationException exp)
            {
                this.messagePanel.ShowWarning(exp.Message);
            }
            catch (Exception exp)
            {
                Logger.Instance(this).Error(exp);
                this.messagePanel.ShowError(Resources.OccurExceptionHaveLogTryLater);
            }
        }

        /// <summary>
        /// Raises the System.Web.UI.Control.Init event.
        /// </summary>
        /// <param name="e"></param>
        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);

            this.messagePanel = new MessagePanel { ID = "MessagePanelExcelUploadPanel" };
            this.Controls.Add(this.messagePanel);
            this.BuildGridViews();
            this.EnsureChildControls();
        }

        private void BuildGridViews()
        {
            this.BuildFailureGridView();
            this.BuildSuccessGridView();
        }

        private void BuildFailureGridView()
        {
            GridViewConfiguration configurationFailure = new GridViewConfiguration()
            {
                EntityName = this.Parser.Document.WorksheetName,
                PageSize = this.PageSize,
                PrimaryKeyFieldName = ExcelParser.ROW_INDEX,
                EnabledCheckBoxField = false,
            };

            List<GridViewFieldConfiguration> fields = new List<GridViewFieldConfiguration>()
					{
						new GridViewFieldConfiguration(ExcelParser.ROW_INDEX, "Excel"+  Resources.Line)
						{
							HeaderStyle = new TableItemStyle() { Width = new Unit("80px") },
							ItemStyle = new TableItemStyle() { HorizontalAlign = HorizontalAlign.Center, Width = new Unit("80px") },
							Sortable = false
						},
						new GridViewFieldConfiguration(ExcelParser.EXCEPTION, Resources.DetailedErrorInformation){ Sortable = false },
					};

            configurationFailure.Fields = fields;

            this.GridViewFailure = new GridViewPanel { ID = "GridViewFailure", Configuration = configurationFailure, Visible = false };
            this.GridViewFailure.DataSourceLoading += new EventHandler<DataSourceLoadEventArgs>(OnGridViewDataSourceLoading);

            HtmlGenericControl header = new HtmlGenericControl("h4") { InnerText = string.Format(Resources.InvalidUploadDataInWorksheet, this.Parser.Document.WorksheetName) };
            header.Style["color"] = "red";

            Container containerFailure = new Container() { Transparent = false };
            containerFailure.Controls.Add(header);
            containerFailure.Controls.Add(this.GridViewFailure);

            this.Controls.Add(containerFailure);
        }

        private void BuildSuccessGridView()
        {
            GridViewConfiguration configuration = new GridViewConfiguration()
            {
                EntityName = this.Parser.Document.WorksheetName,
                PageSize = this.PageSize,
                PrimaryKeyFieldName = this.Parser.Document.PrimaryKeyField.FieldName,
                EnabledCheckBoxField = false,
                DeleteButton = new ButtonConfiguration { Type = ButtonTypes.DeleteImage }
            };

            List<GridViewFieldConfiguration> fields = new List<GridViewFieldConfiguration>();
            foreach (ExcelField excelField in this.Parser.Document.Fields)
            {
                if (excelField.IsDisplayed)
                {
                    GridViewFieldConfiguration field = new GridViewFieldConfiguration(excelField.FieldName, excelField.FieldName);
                    switch (excelField.FieldType)
                    {
                        case ExcelFieldTypes.Double:
                        case ExcelFieldTypes.Decimal:
                        case ExcelFieldTypes.Int32:
                        case ExcelFieldTypes.DateTime:
                            field.ItemStyle = new TableItemStyle() { HorizontalAlign = HorizontalAlign.Center, Wrap = false };
                            field.DisplayFormat = excelField.DisplayedFormat;
                            break;
                    }

                    fields.Add(field);
                }
            }

            configuration.Fields = fields;

            this.GridViewSuccess = new GridViewPanel { ID = "GridViewSuccess", Configuration = configuration, Visible = false };
            this.GridViewSuccess.DataSourceLoading += new EventHandler<DataSourceLoadEventArgs>(OnGridViewDataSourceLoading);
            this.GridViewSuccess.Deleting += (sender, e) =>
                {
                    if (this.Uploaded != null)
                    {
                        DataTable datatable = this.Uploaded.Tables[ExcelParser.SUCCESS];
                        var rowsToDelete = datatable.AsEnumerable().Where(row => row[this.Parser.Document.PrimaryKeyField.FieldName].ToString() == e.PrimaryKey).ToList();
                        foreach (DataRow rowToDelete in rowsToDelete)
                            datatable.Rows.Remove(rowToDelete);

                        datatable.AcceptChanges();
                        this.GridViewSuccess.DataBind();
                    }
                };

            HtmlGenericControl header = new HtmlGenericControl("h4") { InnerText = string.Format(Resources.SuccessfulWorksheetUploadInformation, this.Parser.Document.WorksheetName) };
            header.Style["color"] = "green";

            Container containerSuccess = new Container();
            containerSuccess.Controls.Add(header);
            containerSuccess.Controls.Add(this.GridViewSuccess);

            this.Controls.Add(containerSuccess);
        }

        void OnGridViewDataSourceLoading(object sender, DataSourceLoadEventArgs e)
        {
            GridViewPanel gridview = sender as GridViewPanel;
            DataTable datatable = null;
            if (this.Uploaded != null)
            {
                if (gridview == this.GridViewSuccess) datatable = this.Uploaded.Tables[ExcelParser.SUCCESS];
                else datatable = this.Uploaded.Tables[ExcelParser.FAILURE];

                DataTable clonedTable = datatable.Copy();
                var selectedRows = clonedTable.Select("", e.SortExpression).Skip(e.PageIndex * e.PageSize).Take(e.PageSize).ToList();
                foreach (DataRow row in clonedTable.Rows)
                {
                    if (!selectedRows.Contains(row)) row.Delete();
                }

                clonedTable.AcceptChanges();

                var clonedDataView = clonedTable.AsDataView();
                clonedDataView.Sort = e.SortExpression;
                e.RecordCount = datatable.Rows.Count;
                e.DataSource = clonedDataView;
            }
            else
            {
                e.RecordCount = 0;
                e.DataSource = null;
            }

            gridview.Visible = e.RecordCount > 0;
        }
    }
}
